"""
时间工具模块
"""
import logging
from datetime import datetime, timedelta
import pytz
import time

logger = logging.getLogger(__name__)

class TimeUtils:
    """时间工具类"""
    
    DEFAULT_TIMEZONE = 'Asia/Shanghai'
    DEFAULT_DATE_FORMAT = '%Y-%m-%d'
    DEFAULT_DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
    
    @staticmethod
    def get_current_time(timezone=DEFAULT_TIMEZONE):
        """
        获取当前时间
        
        Args:
            timezone: 时区
        
        Returns:
            datetime: 当前时间
        """
        try:
            tz = pytz.timezone(timezone)
            return datetime.now(tz)
        except Exception as e:
            logger.error(f"获取当前时间失败: {str(e)}")
            raise
    
    @staticmethod
    def get_current_timestamp():
        """
        获取当前时间戳
        
        Returns:
            int: 当前时间戳
        """
        return int(time.time())
    
    @staticmethod
    def format_datetime(dt, format_str=DEFAULT_DATETIME_FORMAT):
        """
        格式化日期时间
        
        Args:
            dt: 日期时间
            format_str: 格式字符串
        
        Returns:
            str: 格式化后的日期时间字符串
        """
        try:
            return dt.strftime(format_str)
        except Exception as e:
            logger.error(f"格式化日期时间失败: {str(e)}")
            raise
    
    @staticmethod
    def parse_datetime(datetime_str, format_str=DEFAULT_DATETIME_FORMAT, timezone=DEFAULT_TIMEZONE):
        """
        解析日期时间字符串
        
        Args:
            datetime_str: 日期时间字符串
            format_str: 格式字符串
            timezone: 时区
        
        Returns:
            datetime: 日期时间对象
        """
        try:
            dt = datetime.strptime(datetime_str, format_str)
            if timezone:
                tz = pytz.timezone(timezone)
                dt = tz.localize(dt)
            return dt
        except Exception as e:
            logger.error(f"解析日期时间字符串失败: {str(e)}")
            raise
    
    @staticmethod
    def get_date_range(start_date, end_date, format_str=DEFAULT_DATE_FORMAT):
        """
        获取日期范围
        
        Args:
            start_date: 开始日期
            end_date: 结束日期
            format_str: 格式字符串
        
        Returns:
            list: 日期列表
        """
        try:
            # 解析日期
            if isinstance(start_date, str):
                start_date = datetime.strptime(start_date, format_str)
            if isinstance(end_date, str):
                end_date = datetime.strptime(end_date, format_str)
            
            # 生成日期范围
            date_range = []
            current_date = start_date
            while current_date <= end_date:
                date_range.append(current_date.strftime(format_str))
                current_date += timedelta(days=1)
            
            return date_range
        except Exception as e:
            logger.error(f"获取日期范围失败: {str(e)}")
            raise
    
    @staticmethod
    def add_days(dt, days):
        """
        添加天数
        
        Args:
            dt: 日期时间
            days: 天数
        
        Returns:
            datetime: 新的日期时间
        """
        try:
            return dt + timedelta(days=days)
        except Exception as e:
            logger.error(f"添加天数失败: {str(e)}")
            raise
    
    @staticmethod
    def add_hours(dt, hours):
        """
        添加小时数
        
        Args:
            dt: 日期时间
            hours: 小时数
        
        Returns:
            datetime: 新的日期时间
        """
        try:
            return dt + timedelta(hours=hours)
        except Exception as e:
            logger.error(f"添加小时数失败: {str(e)}")
            raise
    
    @staticmethod
    def add_minutes(dt, minutes):
        """
        添加分钟数
        
        Args:
            dt: 日期时间
            minutes: 分钟数
        
        Returns:
            datetime: 新的日期时间
        """
        try:
            return dt + timedelta(minutes=minutes)
        except Exception as e:
            logger.error(f"添加分钟数失败: {str(e)}")
            raise
    
    @staticmethod
    def add_seconds(dt, seconds):
        """
        添加秒数
        
        Args:
            dt: 日期时间
            seconds: 秒数
        
        Returns:
            datetime: 新的日期时间
        """
        try:
            return dt + timedelta(seconds=seconds)
        except Exception as e:
            logger.error(f"添加秒数失败: {str(e)}")
            raise
    
    @staticmethod
    def get_time_difference(dt1, dt2, unit='seconds'):
        """
        获取时间差
        
        Args:
            dt1: 日期时间1
            dt2: 日期时间2
            unit: 单位 (seconds, minutes, hours, days)
        
        Returns:
            float: 时间差
        """
        try:
            diff = dt2 - dt1
            
            if unit == 'seconds':
                return diff.total_seconds()
            elif unit == 'minutes':
                return diff.total_seconds() / 60
            elif unit == 'hours':
                return diff.total_seconds() / 3600
            elif unit == 'days':
                return diff.days
            else:
                raise ValueError(f"不支持的单位: {unit}")
        except Exception as e:
            logger.error(f"获取时间差失败: {str(e)}")
            raise
    
    @staticmethod
    def convert_timezone(dt, from_timezone, to_timezone):
        """
        转换时区
        
        Args:
            dt: 日期时间
            from_timezone: 源时区
            to_timezone: 目标时区
        
        Returns:
            datetime: 转换后的日期时间
        """
        try:
            # 确保日期时间有时区信息
            if dt.tzinfo is None:
                from_tz = pytz.timezone(from_timezone)
                dt = from_tz.localize(dt)
            
            # 转换到目标时区
            to_tz = pytz.timezone(to_timezone)
            return dt.astimezone(to_tz)
        except Exception as e:
            logger.error(f"转换时区失败: {str(e)}")
            raise
    
    @staticmethod
    def is_same_day(dt1, dt2):
        """
        判断是否是同一天
        
        Args:
            dt1: 日期时间1
            dt2: 日期时间2
        
        Returns:
            bool: 是否是同一天
        """
        try:
            return dt1.date() == dt2.date()
        except Exception as e:
            logger.error(f"判断是否是同一天失败: {str(e)}")
            raise
    
    @staticmethod
    def get_start_of_day(dt):
        """
        获取一天的开始时间
        
        Args:
            dt: 日期时间
        
        Returns:
            datetime: 一天的开始时间
        """
        try:
            return datetime.combine(dt.date(), datetime.min.time())
        except Exception as e:
            logger.error(f"获取一天的开始时间失败: {str(e)}")
            raise
    
    @staticmethod
    def get_end_of_day(dt):
        """
        获取一天的结束时间
        
        Args:
            dt: 日期时间
        
        Returns:
            datetime: 一天的结束时间
        """
        try:
            return datetime.combine(dt.date(), datetime.max.time())
        except Exception as e:
            logger.error(f"获取一天的结束时间失败: {str(e)}")
            raise
    
    @staticmethod
    def get_start_of_month(dt):
        """
        获取一个月的开始时间
        
        Args:
            dt: 日期时间
        
        Returns:
            datetime: 一个月的开始时间
        """
        try:
            return datetime(dt.year, dt.month, 1)
        except Exception as e:
            logger.error(f"获取一个月的开始时间失败: {str(e)}")
            raise
    
    @staticmethod
    def get_end_of_month(dt):
        """
        获取一个月的结束时间
        
        Args:
            dt: 日期时间
        
        Returns:
            datetime: 一个月的结束时间
        """
        try:
            # 获取下个月的第一天
            if dt.month == 12:
                next_month = datetime(dt.year + 1, 1, 1)
            else:
                next_month = datetime(dt.year, dt.month + 1, 1)
            
            # 减去一秒
            return next_month - timedelta(seconds=1)
        except Exception as e:
            logger.error(f"获取一个月的结束时间失败: {str(e)}")
            raise
    
    @staticmethod
    def get_start_of_week(dt, start_day=0):
        """
        获取一周的开始时间
        
        Args:
            dt: 日期时间
            start_day: 一周的第一天 (0表示周一，6表示周日)
        
        Returns:
            datetime: 一周的开始时间
        """
        try:
            # 获取当前是一周的第几天 (0表示周一，6表示周日)
            weekday = dt.weekday()
            
            # 计算与一周第一天的差距
            days_diff = (weekday - start_day) % 7
            
            # 获取一周的开始日期
            start_date = dt.date() - timedelta(days=days_diff)
            
            return datetime.combine(start_date, datetime.min.time())
        except Exception as e:
            logger.error(f"获取一周的开始时间失败: {str(e)}")
            raise
    
    @staticmethod
    def get_end_of_week(dt, start_day=0):
        """
        获取一周的结束时间
        
        Args:
            dt: 日期时间
            start_day: 一周的第一天 (0表示周一，6表示周日)
        
        Returns:
            datetime: 一周的结束时间
        """
        try:
            # 获取一周的开始时间
            start_of_week = TimeUtils.get_start_of_week(dt, start_day)
            
            # 一周的结束时间是开始时间加上6天的结束时间
            end_date = start_of_week.date() + timedelta(days=6)
            
            return datetime.combine(end_date, datetime.max.time())
        except Exception as e:
            logger.error(f"获取一周的结束时间失败: {str(e)}")
            raise